/*****************************************************************************
*    Ali Corp. All Rights Reserved. 2002 Copyright (C)
*
*    File:    bootloader.c
*
*    Description:    This file contains all globe micros and functions declare
*                    of Flash boot loader.
*    History:
*           Date            Athor        Version          Reason
*       ============    =============   =========   =================
*   1.  Oct.28.2003     Justin Wu       Ver 0.1    Create file.
 *  2.  2006.5.16       Justin Wu       Ver 0.2    STO chunk support & clean up.
*****************************************************************************/
#include <sys_config.h>
#include <sys_parameters.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <api/libchunk/chunk.h>
#include <bus/sci/sci.h>
#include <bus/flash/flash.h>
#include <hal/hal_gpio.h>
#include <hal/hal_mem.h>
#include <hld/pan/pan_dev.h>
#include <hld/pan/pan.h>
#include <bus/i2c/i2c.h>
#include <hld/dis/vpo.h>
#include <hld/decv/decv.h>
#include "tve_hd_setting_half_mode.h"
#define _OTA_E_
#define SYS_CPU_CLOCK_FPGA 13000000
#define US_TICKS       (sys_ic_get_cpu_clock()*1000000 / 2000000)// (SYS_CPU_CLOCK / 2000000)
#define WAIT_300MS      (300000 * US_TICKS)
#define WAIT_150MS      (150000 * US_TICKS) //add for fast boot up
#define WAIT_500MS              (500000 * US_TICKS)
#define WAIT_5MS        (5000   * US_TICKS)

#undef FIXED_PRINTF
#define FIXED_PRINTF     libc_printf
//#define FIXED_PRINTF(...)     do{}while(0)
/* Calcuate InternalBufferSize for 7-zip */
#define LZMA_BASE_SIZE  1846
#define LZMA_LIT_SIZE   768
#define BUFFER_SIZE     ((LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (0 + 2))) * sizeof(UINT16))

#define GET_FILE_SIZE(p)  ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
#define WRITE_UINT8(uAddr, bVal)    do {*(volatile UINT8 *)(uAddr) = (bVal);} while(0)

#ifdef __mips16
#define SDBBP()         asm volatile(".half 0xe801; \
								  nop")
#else
#define SDBBP()         asm volatile(".word	0x7000003f; \
								  nop");
#endif

#ifdef C3041
#define __ATTRIBUTE_BOOT_ __attribute__((section(".boot")))
__ATTRIBUTE_BOOT_ UINT32 stb_gpio = 8;
__ATTRIBUTE_BOOT_ UINT32 clk_gpio = 37;
__ATTRIBUTE_BOOT_ UINT32 data_gpio = 9;
#endif

#ifndef FP_CS_GPIO_NUM
#define FP_CS_GPIO_NUM 95
#endif

#define libc_printf(...)                        do{}while(0)
static struct pan_hw_info pan_hw_info =
{
        0,                              /* type_kb : 2; Key board (array) type */
        1,                              /* type_scan : 1; 0: Slot scan, 1: Shadow scan */
        1,                              /* type_key: 1; Key exit or not */
        1,                              /* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
        0,                              /* type_mcu: 1; MCU exit or not */
        4,                              /* num_com: 4; Number of com PIN, 0 to 8 */
        1,                              /* Position of colon flag, 0 to 7 */
        1,                              /* num_scan: 2; Number of scan PIN, 0 to 2 */
        0,                              /* rsvd_bits:6; Reserved bits */
        0,              /* rsvd byte for align pan_info */
        {0, HAL_GPIO_O_DIR, 127},               /* LATCH PIN */
        {0, HAL_GPIO_O_DIR,     127},           /* CLOCK PIN */
        {1, HAL_GPIO_O_DIR,     127},           /* DATA PIN */
        {       {0, HAL_GPIO_I_DIR,    127},           /* SCAN1 PIN */
                {0, HAL_GPIO_I_DIR, 127}
        },              /* SCAN2 PIN */
        {       {0, HAL_GPIO_O_DIR,    127},           /* COM1 PIN */
                {0, HAL_GPIO_O_DIR,     127},           /* COM2 PIN */
                {0, HAL_GPIO_O_DIR,     127},           /* COM3 PIN */
                {0, HAL_GPIO_O_DIR,     127},           /* COM4 PIN */
                {0, HAL_GPIO_O_DIR, 127},               /* COM5 PIN */
                {0, HAL_GPIO_O_DIR, 127},               /* COM6 PIN */
                {0, HAL_GPIO_O_DIR, 127},               /* COM7 PIN */
                {0, HAL_GPIO_O_DIR, 127}
        },              /* COM8 PIN */
        {       {0, HAL_GPIO_O_DIR,    127},           /* POWER PIN */
                {1, HAL_GPIO_O_DIR,     127},           /* LOCK PIN */
                {0, HAL_GPIO_O_DIR, 127},               /* Extend function LBD */
                {0, HAL_GPIO_O_DIR, 127}
        },              /* Extend function LBD */
        {0, HAL_GPIO_O_DIR, 127},       /* rsvd extend function LBD */
        300,                                                    /* Intv repeat first */
        250,                                                    /* Intv repeat */
        350,                                                        /* Intv release, 0: disable release key */
        NULL,                                                   /* hook_scan() callback */
        NULL,                                                   /* hook_show() callback */
};
#define bitmap_list                             NULL
#define bitmap_list_num         0
struct pan_configuration pan_config = {&pan_hw_info, bitmap_list_num, bitmap_list};
struct pan_device *panel_dev;

#ifdef _BOARD_DB_M3805_01V01_
#define SDA_POSTION 30
#define SCL_POSTION 9
#else
#define SDA_POSTION 9
#define SCL_POSTION 31
#endif


struct sto_device *flash_dev;

UINT16 g_blogo_format = 0;  /* Bootloader logo parameters */
UINT8  g_second_loader = 0;
UINT8  g_crc_bad;

extern int gzip_decompress ( UINT8 *, UINT8 *, UINT8 * );
extern int un7zip ( UINT8 *, UINT8 *, UINT8 * );
extern int unlzo ( UINT8 *, UINT8 *, UINT8 * ); //add for fast boot up

#define SEE_CODE  1
#define MAIN_CODE 0
#define MAIN_ENTRY 0x80000200
#define SEE_TEMP 0xa1a00200
#define MAIN_TEMP 0x81e80000

static UINT32 g_ota_offset = 0;
static UINT8 find_second_loader()
{
#ifdef _OTA_E_
#define C_SECTOR_SIZE   0x10000
        UINT8 *buffer;
        UINT32 data_id;
        UINT32 data_len;
        UINT32 data_off;
        UINT32 data_crc;
        UINT32 crc;
        UINT32 pointer = 0;

        UINT8 bSecondOta = 0;

        while ( pointer < flash_dev->totol_size )
        {
                data_id  = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_ID );
                data_len = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_LENGTH );
                data_off = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_OFFSET );
                data_crc = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_CRC );
                if ( data_len && ( data_len < data_off ) && ( data_crc != NO_CRC ) && ( ( data_id & CHUNKID_SECLOADER_MASK ) == CHUNKID_SECLOADER ) )
                {
                        buffer = ( UINT8 * ) MALLOC ( data_len );
                        if ( buffer != NULL )
                        {
                                sto_get_data ( flash_dev, buffer, pointer + 16, data_len );
                                crc = MG_Table_Driven_CRC ( 0xFFFFFFFF, buffer, data_len );
                                FREE ( buffer );
                                if ( data_crc == crc )
                                {
                                        g_ota_offset = pointer;
                                        bSecondOta = 1;
                                        break;
                                }
                        }
                }
                pointer += C_SECTOR_SIZE;
        }

        //verify the second loader.
        if ( bSecondOta )
        {
                pointer = g_ota_offset;
                do
                {
                        data_id  = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_ID );
                        data_len = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_LENGTH );
                        data_off = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_OFFSET );
                        data_crc = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_CRC );

                        /*
                        if (pointer != 0)
                        {
                            if ((data_id >> 16) & 0xFF + (data_id >> 24) & 0xFF != 0xFF)
                            {
                                bSecondOta = 0;
                                break;
                            }
                        }
                        */
                        FIXED_PRINTF ( "2.6!\n" );
                        if ( data_off > flash_dev->totol_size )
                        {
                                FIXED_PRINTF ( "@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                                               pointer, data_id, data_off );
                                bSecondOta = 0;
                                break;
                        }
                        if ( ( data_off != 0 ) && ( data_len > data_off ) )
                        {
                                FIXED_PRINTF ( "@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                                               pointer, data_id, data_len, data_off );
                                bSecondOta = 0;
                                break;
                        }
                        if ( data_crc != NO_CRC )
                        {
                                if ( ( buffer = ( UINT8 * ) MALLOC ( data_len ) ) == NULL )
                                        ASSERT ( 0 );
                                sto_get_data ( flash_dev, buffer, pointer + 16, data_len );
                                crc = MG_Table_Driven_CRC ( 0xFFFFFFFF, buffer, data_len );
                                FREE ( buffer );
                                FIXED_PRINTF ( "2.7!\n" );
                                if ( data_crc != crc )
                                {
                                        FIXED_PRINTF ( "@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                                                       pointer, data_id, crc, data_crc );
                                        bSecondOta = 0;
                                        break;
                                }
                        }
                        pointer += data_off;
                        if ( pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size )
                        {
                                FIXED_PRINTF ( "@pointer[%08X] no space for header\n", pointer );
                                bSecondOta = 0;
                                break;
                        }

                }
                while ( data_off );
        }
        if ( 0 == bSecondOta )
                g_ota_offset = 0;
        return bSecondOta;
#endif
        return 0;
}


UINT8 check_program ( void )
{
        UINT32 i;
        UINT8 *buffer;
        UINT32 data_id;
        UINT32 data_len;
        UINT32 data_off;
        UINT32 data_crc;
        UINT32 crc;
        UINT32 pointer = 0;
        FIXED_PRINTF ( "check_program!\n" );
        g_second_loader = find_second_loader();
        do
        {
                data_id  = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_ID );
                data_len = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_LENGTH );
                data_off = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_OFFSET );
                data_crc = sto_fetch_long ( ( UINT32 ) pointer + CHUNK_CRC );

                if ( pointer != 0 )
                {
                        if ((( data_id >> 16 ) & 0xFF) + (( data_id >> 24 ) & 0xFF) != 0xFF )
                                return 1;
                }
                if ( data_off > flash_dev->totol_size )
                {
                        FIXED_PRINTF ( "@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                                       pointer, data_id, data_off );
                        return 2;
                }
                if ( ( data_off != 0 ) && ( data_len > data_off ) )
                {
                        FIXED_PRINTF ( "@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                                       pointer, data_id, data_len, data_off );
                        return 3;
                }
                if ( data_crc != NO_CRC )
                {
                        if ( ( buffer = ( UINT8 * ) MALLOC ( data_len ) ) == NULL )
                                ASSERT ( 0 );
                        sto_get_data ( flash_dev, buffer, pointer + 16, data_len );
                        crc = MG_Table_Driven_CRC ( 0xFFFFFFFF, buffer, data_len );
                        FREE ( buffer );
                        if ( data_crc != crc )
                        {
                                FIXED_PRINTF ( "@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                                               pointer, data_id, crc, data_crc );
                                return 4;
                        }
                }
                pointer += data_off;
                if ( pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size )
                {
                        FIXED_PRINTF ( "@pointer[%08X] no space for header\n", pointer );
                        return 5;
                }

        }
        while ( data_off );

        return 0;
}

extern UINT32 g_see_entry;
extern UINT32 g_see_length;
extern UINT32 g_see_ram_base;

UINT8 *expand ( UINT32 offset, int unzip ( UINT8 *, UINT8 *, UINT8 * ), UINT32 type )
{
        UINT8 *entry;
        UINT8 *buffer;
        UINT32 code_len;
        UINT8 *codestart;

        //add for fast boot up
        UINT8 ret = 0;
        UINT8* flag;

        codestart = ( UINT8 * ) sto_fetch_long ( ( UINT32 ) offset + CHUNK_CODESTART );
        entry = ( UINT8 * ) sto_fetch_long ( ( UINT32 ) offset + CHUNK_ENTRY );
        if ( codestart == 0 || codestart == ( UINT8 * ) 0xFFFFFFFF )
        {
                if ( type == MAIN_CODE )   codestart = ( UINT8 * ) MAIN_ENTRY;
                if ( type == SEE_CODE )    codestart = ( UINT8 * ) SEE_TEMP;
        }
        if ( entry == 0 || entry == ( UINT8 * ) 0xFFFFFFFF )
                entry = codestart;
        /* Copy compressed code into DRAM */
        code_len = sto_fetch_long ( ( UINT32 ) offset + CHUNK_LENGTH );
        if ( type == MAIN_CODE )
                sto_get_data ( flash_dev, ( void * ) ( MAIN_TEMP - code_len ), offset + CHUNK_HEADER_SIZE, code_len );
        if ( type == SEE_CODE )
                // 2*chunk_head_size because there two chunk before see_code
                sto_get_data ( flash_dev, ( void * ) ( MAIN_TEMP - code_len ), offset + CHUNK_HEADER_SIZE, code_len );
        buffer = MALLOC ( BUFFER_SIZE );
        if ( buffer == NULL )
        {
                FIXED_PRINTF ( "Boot loader: No decompress buffer!\n" );
                entry = 0;
        }
        else
        {
                //add for fast boot up
                flag = ( UINT8 * ) ( MAIN_TEMP - code_len );

                if ( type == MAIN_CODE )
                {
                        //change for fast boot up, lzma must have 4 bytes: 0x6c 0x00 0x00 0x80
                        if ( flag[0] == 0x6c && flag[1] == 0x0 && flag[2] == 0x0 && flag[3] == 0x80 )
                                ret = unzip ( ( void * ) ( MAIN_TEMP - code_len ), codestart, buffer );
                        else
                                ret = unlzo ( ( void * ) ( MAIN_TEMP - code_len ), codestart, buffer );

                        if ( ret != 0 )
                        {
                                FIXED_PRINTF ( "Boot loader: Decompress error!\n" );
                                entry = 0;
                        }
                }
                if ( type == SEE_CODE )
                {
                        //change for fast boot up, lzma must have 4 bytes: 0x6c 0x00 0x00 0x80
                        if ( flag[0] == 0x6c && flag[1] == 0x0 && flag[2] == 0x0 && flag[3] == 0x80 )
                                ret = unzip ( ( void * ) ( MAIN_TEMP - code_len ), codestart, buffer );
                        else
                                ret = unlzo ( ( void * ) ( MAIN_TEMP - code_len ), codestart, buffer );

                        if ( ret != 0 )
                        {
                                FIXED_PRINTF ( "SEE Boot loader: Decompress error!\n" );
                                entry = 0;
                        }
                        else
                        {
                                * ( UINT32 * ) ( ( UINT32 ) ( &g_see_length ) | 0xa0000000 ) = * ( UINT32* ) buffer;
                        }
                }
                FREE ( buffer );
        }

        return entry;
}

static void pin_mux_set ( UINT32 value, UINT8 start_bit, UINT8 bit_num )
{
        UINT32 reg_tmp;
        UINT32 mask = 0, i, tmp;

        reg_tmp = * ( ( volatile UINT32 * ) 0xb8000028 );
        tmp = 1;
        for ( i = 0; i < bit_num; i++ )
        {
                tmp <<= 1;
                tmp |= 1;
        }
        mask = ~ ( tmp << start_bit );

        reg_tmp &= mask;
        reg_tmp |= ( value << start_bit );

        * ( ( volatile UINT32 * ) 0xb8000028 ) = reg_tmp;
}

/*
ota data backup header:
|backup start flag  |backup end flag|
|  16bytes mark   |     4bytes          |
backup address: 0xbfd20000
*/
#define UN7ZIP_BUFF_ADDR    0xA0460000;
#define UN7ZIP_SWAP_ADDR    0xA0400000
#define BACKUP_START_FLAG   0x55aa5a5a

#define OTA_BACKUP_OFFSET 16

UINT8 b_end_mark[16] = {0x65, 0x72, 0x6F, 0x74, 0x73, 0x65, 0x72, 0x5F, 0x67, 0x6F, 0x72, 0x70, 0x5F, 0x61, 0x74, 0x6F}; /* erotser_gorp_ato*/

UINT32 ota_get_restore_addr()
{
        UINT32 f_addr;
        UINT32 buf;

        f_addr = SYS_FLASH_BASE_ADDR + flash_dev->totol_size;

        // search ota retore addr from end to start
        while ( f_addr > SYS_FLASH_BASE_ADDR )
        {
                // find sector ahead
                f_addr -= 64 * 1024;
                // align to 64k
                //f_addr = f_addr - f_addr%(64*1024);
                f_addr &= 0xffff0000;

                if ( * ( UINT32 * ) ( f_addr + OTA_BACKUP_OFFSET ) == BACKUP_START_FLAG )
                        return f_addr;
        }

        return 0xFFFFFFFF;
}

INT32  ota_prog_restore()
{
        UINT32 write_size, param;
        UINT32 offset, code_size, ota_data_size, check_size, check_crc;
        UINT8 i = 0;
        UINT8 buf[16];
        UINT8 *un7zip_buff;
        UINT8 *swap_buff;
        UINT8 *block_addr;
        UINT8 *f_block_addr;
        UINT8 *userdb_addr;
        UINT32 b_addr;
        UINT32 chid = 0x04FB0100;

        /* check if restore data exist */
        b_addr = ota_get_restore_addr();
        if ( b_addr == 0xFFFFFFFF )
                return -1;
        MEMCPY ( buf, ( UINT8* ) b_addr, 16 );
        if ( MEMCMP ( b_end_mark, buf, 16 ) == 0 ) /* found restore data */
        {
                un7zip_buff = ( UINT8 * ) UN7ZIP_BUFF_ADDR;
                swap_buff = ( UINT8 * ) UN7ZIP_SWAP_ADDR;
                /* de-compress restore data */
                if ( un7zip ( ( UINT8* ) ( b_addr + 16 + 4 ), un7zip_buff, swap_buff ) != 0 )
                {
                        FIXED_PRINTF ( "un7zip restore data failed.\n" );
#ifdef PANEL_DISPLAY
                        pan_display ( panel_dev, "E001", 4 );
#endif
                        return -1;
                }
                /* check CRC */
                ota_data_size = * ( ( UINT32* ) swap_buff );
                FIXED_PRINTF ( "Check CRC...\n" );

                MG_Setup_CRC_Table();
                offset = 0;
                block_addr = un7zip_buff;
                code_size = ota_data_size;
                FIXED_PRINTF ( "block_addr = 0x%8x \n", block_addr );
                FIXED_PRINTF ( "code_size = 0x%8x \n", code_size );
                do
                {
                        block_addr += offset;
                        check_size = ( block_addr[4] << 24 )
                                     + ( block_addr[5] << 16 )
                                     + ( block_addr[6] << 8 )
                                     + block_addr[7];

                        offset =        ( block_addr[8] << 24 )
                                        + ( block_addr[9] << 16 )
                                        + ( block_addr[10] << 8 )
                                        + block_addr[11];

                        if ( offset > code_size )
                        {
                                FIXED_PRINTF ( "ERROR : size NOT enough !\n" );
#ifdef PANEL_DISPLAY
                                pan_display ( panel_dev, "E002", 4 );
#endif
                                return -1;
                        }
                        code_size -= offset;


                        check_crc = ( block_addr[12] << 24 )
                                    + ( block_addr[13] << 16 )
                                    + ( block_addr[14] << 8 )
                                    + block_addr[15];
                        FIXED_PRINTF ( "crc = 0x%8x \n", check_crc );
                        if ( check_crc != NO_CRC )
                        {
                                if ( check_crc != ( UINT32 ) MG_Table_Driven_CRC ( 0xFFFFFFFF, block_addr + 0x10, check_size ) )
                                {
                                        FIXED_PRINTF ( "ERROR : CRC error !\n" );
#ifdef PANEL_DISPLAY
                                        pan_display ( panel_dev, "E003", 4 );
#endif
                                        return -1;
                                }
                        }
                }
                while ( offset != 0 && code_size > 0 );
                /* if CRC is OK, then start burning flash */
                ota_data_size = b_addr - SYS_FLASH_BASE_ADDR;
                code_size = ota_data_size;
                block_addr = un7zip_buff;
                f_block_addr = 0;
                if ( sto_lseek ( flash_dev, 0, STO_LSEEK_SET ) != 0 )
                {
                        return -1;
                }
                if ( sto_read ( flash_dev, swap_buff, 64 * 1024 ) != 64 * 1024 )
                {
                        FIXED_PRINTF ( "ERROR: sto_read failed!\n" );
                        return -1;
                }

                /* find position of userdb */
                chunk_init ( ( UINT32 ) un7zip_buff, 0x200000 );
                userdb_addr = chunk_goto ( &chid, 0xFFFFFFFF, 1 ) ;
                code_size = ( userdb_addr - un7zip_buff );
                code_size += 0x80; /* user db chunk header */

                offset =    ( swap_buff[8] << 24 )
                            + ( swap_buff[9] << 16 )
                            + ( swap_buff[10] << 8 )
                            + swap_buff[11];
                f_block_addr += offset; //skip bootloader of flash address
                code_size -= offset;
                ota_data_size -= offset;
                block_addr += offset; //skip bootloader of sdram address
                while ( code_size )
                {
                        write_size = ( code_size < 64 * 1024 ) ? code_size : 64 * 1024;

                        /* Uper 22 bits of MSB is start offset based on SYS_FLASH_BASE_ADDR */
                        //param = ( UINT32 ) f_block_addr;
                       // param = param << 10;
                        /* Lower 10 bits of LSB is length in K bytes*/
                       // param += ( 64 * 1024 ) >> 10;
                        //if ( sto_io_control ( flash_dev, STO_DRIVER_SECTOR_ERASE, param ) != SUCCESS )
                        UINT32 tmp_param[2];
												tmp_param[0] = (UINT32) f_block_addr;
												tmp_param[1] = (64*1024)>>10;
												param= (UINT32)tmp_param;
												if ( sto_io_control ( flash_dev, STO_DRIVER_SECTOR_ERASE_EXT, param ) != SUCCESS )//Summic add for check the >=4M Flash
                        {
                                FIXED_PRINTF ( "ERROR: erase flash memory failed!\n" );
                                return -1;
                        }
                        if ( sto_lseek ( flash_dev, ( INT32 ) f_block_addr, STO_LSEEK_SET ) != ( INT32 ) f_block_addr )
                        {
                                FIXED_PRINTF ( "ERROR: sto_lseek failed!\n" );
                                return -1;
                        }
                        if ( sto_write ( flash_dev, block_addr, write_size ) != write_size )
                        {
                                FIXED_PRINTF ( "ERROR: sto_write failed!\n" );
                                return -1;
                        }
                        f_block_addr += ( 64 * 1024 );
                        block_addr += write_size;
                        code_size -= write_size;
#ifdef PANEL_DISPLAY
//          sprintf(buf,"%x",((ota_data_size-code_size)*100/ota_data_size));
                        if ( i % 2 == 0 )
                                pan_display ( panel_dev, "_-_-", 4 );
                        else
                                pan_display ( panel_dev, "-_-_", 4 );
                        i++;
#endif
                }
                return 0;

        }
        else
        {
#ifdef PANEL_DISPLAY
                pan_display ( panel_dev, "Err ", 4 );
#endif
        }
        return -1;
}

void clean_restore_data()
{
        UINT32 param;
        UINT32 b_addr;

        b_addr = ota_get_restore_addr();
        if ( b_addr != 0xFFFFFFFF )
        {
#ifdef PANEL_DISPLAY
                pan_display ( panel_dev, "CLr ", 4 );
#endif
                /* Uper 22 bits of MSB is start offset based on SYS_FLASH_BASE_ADDR */
               // param = b_addr - SYS_FLASH_BASE_ADDR;
               // param = param << 10;
                /* Lower 10 bits of LSB is length in K bytes*/
               // param += ( flash_dev->totol_size - ( b_addr - SYS_FLASH_BASE_ADDR ) ) >> 10;
               // if ( sto_io_control ( flash_dev, STO_DRIVER_SECTOR_ERASE, param ) != SUCCESS )
               UINT32 tmp_param[2];
								tmp_param[0] = b_addr - SYS_FLASH_BASE_ADDR;
								tmp_param[1] = (flash_dev->totol_size-(b_addr - SYS_FLASH_BASE_ADDR))>>10;
								param= (UINT32)tmp_param;
							if ( sto_io_control ( flash_dev, STO_DRIVER_SECTOR_ERASE_EXT, param ) != SUCCESS ) //Summic add for check the >=4M Flash
               	{
                        FIXED_PRINTF ( "ERROR: clean restore data  failed!\n" );
                        return;
                }
        }
}

static void set_os_config()
{
        struct os_config *ptr = ( struct os_config * ) 0xa00001e0;

        ptr->task_num = 0;
        ptr->sema_num = 0;
        ptr->flg_num = 0;
        ptr->mbf_num = 0;
        ptr->mutex_num = 0;
        ptr->parity_value = ptr->task_num + ptr->sema_num + ptr->flg_num + ptr->mbf_num + ptr->mutex_num;
}

static void bl_GPIO_init()
{
#ifdef _BOARD_DB_M3805_01V01_  //01v02
        static UINT32 data[3] = {0x40000200, 0x0, 0x0};
#else
        static UINT32 data[3] = {0x80000200, 0x0, 0x0};
#endif
        UINT32 reg_addr[] =
        {
                GPIO_REG, GPIOA_REG, GPIOB_REG, //GPIOC_REG, GPIOD_REG,
        };
        UINT32 i, j, value;

        // disable all GPIO
        for ( i = 0; i < sizeof ( reg_addr ) / sizeof ( reg_addr[0] ); i++ )
        {
                value = data[i];
                * ( ( volatile unsigned long * ) reg_addr[i] ) = value;
        }
}
static void bl_uart_init()
{
#ifndef ENABLE_EROM
        libc_printf_uart_id_set ( 0 );
        sci_16550uart_attach ( 1 ); /* Use just 1 UART for RS232 */
        sci_mode_set ( SCI_FOR_RS232, 115200, SCI_PARITY_EVEN );
        FIXED_PRINTF ( "APP  init!\n" );
#endif
}


static void bl_panel_init()
{
        UINT32 data;
#ifdef PANEL_DISPLAY
        FIXED_PRINTF ( "bl_panel_init!\n" );
        /* Init front panel and IR */
        data = * ( ( unsigned char * ) 0xb8000088 );
        data |= 0x9;
        * ( ( unsigned char * ) 0xb8000088 ) = data;

        i2c_scb_attach ( 1 );
        i2c_gpio_attach ( 1 );
        i2c_gpio_set ( 0, SDA_POSTION, SCL_POSTION );           // SCART/panel
        extern void pan_ch455_id_set ( struct pan_device * dev, UINT32 id );
        pan_ch455_attach ( &pan_config );
        panel_dev = ( struct pan_device * ) dev_get_by_id ( HLD_DEV_TYPE_PAN, 0 );
        pan_ch455_id_set ( panel_dev, I2C_TYPE_GPIO );

        pan_open ( panel_dev );
        pan_display ( panel_dev, " ON ", 4 );
#endif
}
static void bl_flash_init()
{
        UINT32 flash_speed;

        FIXED_PRINTF ( "bl_flash_init!\n" );
        * ( ( unsigned long * ) 0xb802e098 ) |=  0xc6000000; //for flash can read 4M
#ifndef ENABLE_SERIAL_FLASH
        flash_info_pl_init();
        sto_local_flash_attach ( NULL );
#else
        flash_info_sl_init();
        sto_local_sflash_attach ( NULL );
#endif
        flash_dev = ( struct sto_device * ) dev_get_by_type ( NULL, HLD_DEV_TYPE_STO );
        if ( flash_dev == NULL )
        {
                FIXED_PRINTF ( "Can't find FLASH device!\n" );
        }
        sto_open ( flash_dev );
        sto_chunk_init ( 0, flash_dev->totol_size );
        sto_get_data ( flash_dev, &flash_speed, HW_SET_FLASHSPEED, 1 );
        flash_speed &= 0x3F;
        if ( flash_speed == 0 )
                flash_speed = HW_FLASH_DEFSPEED;
        HAL_ROM_MODE_SET ( flash_speed, 0, 1, 0 );
}
static bl_verify_sw()
{

        FIXED_PRINTF ( "bl_verify_sw\n" );
        MG_Setup_CRC_Table();//Rs232 upgrade must use
        g_crc_bad = check_program();
        if ( g_crc_bad )
                FIXED_PRINTF ( "crc error!\n" );
}

struct vdec_device*  g_decv_dev = NULL;
//struct vdec_device*  g_decv_avc_dev = NULL;
//struct vdec_device*  g_decv_dev2 = NULL;
struct vpo_device*   g_vpo_dev = NULL;
struct vpo_device*   g_sd_vpo_dev = NULL;
#define VDAC_USE_CVBS_TYPE      CVBS_1
#define VDAC_USE_RGB_TYPE       RGB_1
#define VDAC_USE_YUV_TYPE       YUV_1

#define CVBS_DAC                DAC3
#define RGB_DAC_R               DAC0
#define RGB_DAC_G               DAC1
#define RGB_DAC_B               DAC2

#define YUV_DAC_V               DAC0
#define YUV_DAC_Y               DAC1
#define YUV_DAC_U               DAC2

void avStart()
{
        struct VDecPIPInfo vInitInfo;
        struct MPSource_CallBack vMPCallBack;
        struct PIPSource_CallBack vPIPCallBack;
        struct VDec_PullDown_Opr tPullDownCallBack;
        struct vp_win_config_para win_para;

        vdec_profile_level ( g_decv_dev, MP_HL, NULL );
        vdec_sync_mode ( g_decv_dev, VDEC_SYNC_FREERUN, VDEC_SYNC_I | VDEC_SYNC_P | VDEC_SYNC_B );
}

void avEnd()
{
        struct VDecPIPInfo vInitInfo;
        struct MPSource_CallBack vMPCallBack;
        struct PIPSource_CallBack vPIPCallBack;
        struct VDec_PullDown_Opr tPullDownCallBack;
        struct vp_win_config_para win_para;

        vdec_profile_level ( g_decv_dev, MP_HL, NULL );
        enum TVSystem  tvsys;       

        vInitInfo.adv_setting.init_mode = 0;
        vInitInfo.adv_setting.out_sys = LINE_1080_25;
        vInitInfo.adv_setting.bprogressive = 0;

        vdec_set_output ( g_decv_dev, MP_MODE, &vInitInfo, &vMPCallBack, &vPIPCallBack );
        
        vpo_win_mode ( g_vpo_dev, VPO_MAINWIN, &vMPCallBack, &vPIPCallBack );
       

}


void InitVPPara_sd ( struct VP_InitInfo *pVPInitInfo )
{
        int i;

        MEMSET ( pVPInitInfo, 0, sizeof ( struct VP_InitInfo ) );

        pVPInitInfo->device_priority = VPO_AUTO_DUAL_OUTPUT;    // S3602F use VCAP
        //api set backgound color]
        pVPInitInfo->tInitColor.uY = 0x10;
        pVPInitInfo->tInitColor.uCb = 0x80;
        pVPInitInfo->tInitColor.uCr = 0x80;
        //set advanced control
        pVPInitInfo->bBrightnessValue = 0;
        pVPInitInfo->fBrightnessValueSign = TRUE;
        pVPInitInfo->wContrastValue = 0;
        pVPInitInfo->fContrastSign = TRUE;
        pVPInitInfo->wSaturationValue = 0;
        pVPInitInfo->fSaturationValueSign = TRUE;
        pVPInitInfo->wSharpness = 0;
        pVPInitInfo->fSharpnessSign = TRUE;
        pVPInitInfo->wHueSin = 0;
        pVPInitInfo->fHueSinSign = TRUE;
        pVPInitInfo->wHueCos = 0;
        pVPInitInfo->fHueCosSign = TRUE;
        //VPO_Zoom
        pVPInitInfo->tSrcRect.uStartX = 0;
        pVPInitInfo->tSrcRect.uWidth = PICTURE_WIDTH;
        pVPInitInfo->tSrcRect.uStartY = 0;
        pVPInitInfo->tSrcRect.uHeight = PICTURE_HEIGHT;
        pVPInitInfo->DstRect.uStartX = 0;
        pVPInitInfo->DstRect.uWidth = SCREEN_WIDTH;
        pVPInitInfo->DstRect.uStartY = 0;
        pVPInitInfo->DstRect.uHeight = SCREEN_HEIGHT;

        //VPO_SetAspect
        pVPInitInfo->eTVAspect = TV_4_3;
        pVPInitInfo->eDisplayMode = NORMAL_SCALE;//LETTERBOX;
        pVPInitInfo->uNonlinearChangePoint = 111;
        pVPInitInfo->uPanScanOffset = 90;
        //VPO_SetOutput
        for ( i = 0; i < VP_DAC_TYPENUM; i++ )
                pVPInitInfo->pDacConfig[i].bEnable = FALSE;

//CVBS_1

        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bEnable = TRUE;


        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].tDacIndex.uDacFirst = CVBS_DAC;

        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].eVGAMode = VGA_NOT_USE;
        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bProgressive = FALSE;

        pVPInitInfo->pDacConfig[YUV_1].bEnable = FALSE;

        //RGB
        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bEnable = FALSE;

        pVPInitInfo->eTVSys = PAL;

        pVPInitInfo->bWinOnOff = FALSE;

        pVPInitInfo->uWinMode = VPO_MAINWIN;//|VPO_PIPWIN;
        pVPInitInfo->tPIPCallBack.RequestCallback = NULL;
        pVPInitInfo->tPIPCallBack.ReleaseCallback = NULL;
        pVPInitInfo->pSrcChange_CallBack = NULL;
}


void InitVPPara ( struct VP_InitInfo *pVPInitInfo )
{
        int i;
        BOOL vdac_progressive = FALSE;

        //api set backgound color]
        pVPInitInfo->tInitColor.uY = 0x10;
        pVPInitInfo->tInitColor.uCb = 0x80;
        pVPInitInfo->tInitColor.uCr = 0x80;

        //set advanced control
        pVPInitInfo->bBrightnessValue = 0;
        pVPInitInfo->fBrightnessValueSign = TRUE;
        pVPInitInfo->wContrastValue = 0;
        pVPInitInfo->fContrastSign = TRUE;
        pVPInitInfo->wSaturationValue = 0;
        pVPInitInfo->fSaturationValueSign = TRUE;
        pVPInitInfo->wSharpness = 0;
        pVPInitInfo->fSharpnessSign = TRUE;
        pVPInitInfo->wHueSin = 0;
        pVPInitInfo->fHueSinSign = TRUE;
        pVPInitInfo->wHueCos = 0;
        pVPInitInfo->fHueCosSign = TRUE;
        pVPInitInfo->bCCIR656Enable = FALSE;
        //VPO_Zoom
        pVPInitInfo->tSrcRect.uStartX = 0;
        pVPInitInfo->tSrcRect.uWidth = PICTURE_WIDTH;
        pVPInitInfo->tSrcRect.uStartY = 0;
        pVPInitInfo->tSrcRect.uHeight = PICTURE_HEIGHT;
        pVPInitInfo->DstRect.uStartX = 0;
        pVPInitInfo->DstRect.uWidth = SCREEN_WIDTH;
        pVPInitInfo->DstRect.uStartY = 0;
        pVPInitInfo->DstRect.uHeight = SCREEN_HEIGHT;

        //VPO_SetAspect
        pVPInitInfo->eTVAspect = TV_4_3;
        pVPInitInfo->eDisplayMode = NORMAL_SCALE;//LETTERBOX;
        pVPInitInfo->uNonlinearChangePoint = 111;
        pVPInitInfo->uPanScanOffset = 90;
        //VPO_SetOutput
        for ( i = 0; i < VP_DAC_TYPENUM; i++ )
                pVPInitInfo->pDacConfig[i].bEnable = FALSE;

        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bEnable = FALSE;
        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].tDacIndex.uDacFirst = CVBS_DAC;
        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].eVGAMode = VGA_NOT_USE;
        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bProgressive = FALSE;

        pVPInitInfo->pDacConfig[YUV_1].bEnable = TRUE;
        pVPInitInfo->pDacConfig[YUV_1].tDacIndex.uDacFirst = YUV_DAC_Y;
        pVPInitInfo->pDacConfig[YUV_1].tDacIndex.uDacSecond = YUV_DAC_U;
        pVPInitInfo->pDacConfig[YUV_1].tDacIndex.uDacThird = YUV_DAC_V;
        pVPInitInfo->pDacConfig[YUV_1].eVGAMode = VGA_NOT_USE;
        pVPInitInfo->pDacConfig[YUV_1].bProgressive = FALSE;

        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bEnable = FALSE;
        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].tDacIndex.uDacFirst = RGB_DAC_R;
        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].tDacIndex.uDacSecond = RGB_DAC_G;
        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].tDacIndex.uDacThird = RGB_DAC_B;
        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].eVGAMode = VGA_NOT_USE;
        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bProgressive = FALSE;

        pVPInitInfo->eTVSys = LINE_1080_25;
        pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bEnable = FALSE;

        pVPInitInfo->pDacConfig[VDAC_USE_YUV_TYPE].bEnable = TRUE;

        pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bEnable = FALSE;

        pVPInitInfo->bWinOnOff = FALSE;
        pVPInitInfo->uWinMode = VPO_MAINWIN;//|VPO_PIPWIN;
        pVPInitInfo->tPIPCallBack.RequestCallback = NULL;
        pVPInitInfo->tPIPCallBack.ReleaseCallback = NULL;
        pVPInitInfo->pSrcChange_CallBack = NULL;
}


RET_CODE avInit()
{
        struct VP_InitInfo      tVPInitInfo;
        UINT32 ret;
        g_vpo_dev = ( struct vpo_device * ) dev_get_by_id ( HLD_DEV_TYPE_DIS, 0 );
        g_sd_vpo_dev = ( struct vpo_device * ) dev_get_by_id ( HLD_DEV_TYPE_DIS, 1 );
        g_decv_dev = ( struct vdec_device * ) dev_get_by_id ( HLD_DEV_TYPE_DECV, 0 );
        ret = vdec_open ( g_decv_dev );
        InitVPPara ( &tVPInitInfo );
        ret = vpo_open ( g_vpo_dev, &tVPInitInfo );
        InitVPPara_sd ( &tVPInitInfo );
        ret = vpo_open ( g_sd_vpo_dev, &tVPInitInfo );
        osal_delay (100000);

        return RET_SUCCESS;
}

#define YUV_SMPTE
#define TVE_CC_BY_VBI   1
#define TVE_TTX_BY_VBI  2
#define TVE_WSS_BY_VBI  4
#define CGMS_WSS_BY_VBI  8
#define YUV_SMPTE       0x10
#define YUV_BETACAM     0x20
#define YUV_MII         0x40

#define SYS_525_LINE    0
#define SYS_625_LINE    1

static void vpo_dev_attach ( void )
{
        struct VP_Feature_Config vp_config;
        struct Tve_Feature_Config tve_config;
        struct Tve_Feature_Config sd_tve_config;

        MEMSET ( ( void * ) &tve_config, 0, sizeof ( struct Tve_Feature_Config ) );
        MEMSET ( ( void * ) &sd_tve_config, 0, sizeof ( struct Tve_Feature_Config ) );
        MEMSET ( ( void * ) &vp_config, 0, sizeof ( struct VP_Feature_Config ) );

        vp_config.bAvoidMosaicByFreezScr = FALSE;    /* macro VDEC_AVOID_MOSAIC_BY_FREEZE_SCR */

        vp_config.bMHEG5Enable = FALSE;                  /* macro  _MHEG5_ENABLE_ */

        vp_config.bOsdMulitLayer = FALSE;                  /* macro OSD_MULTI_LAYER */
        vp_config.bOvershootSolution = FALSE;            /* macro VIDEO_OVERSHOOT_SOLUTION */
        vp_config.bP2NDisableMAF = TRUE;
        vp_config.bSupportExtraWin = FALSE;                /* macro VIDEO_SUPPORT_EXTRA_DVIEW_WINDOW */
        vp_config.bADPCMEnable = FALSE;                   /* macro VIDEO_ADPCM_ONOFF(VIDEO_ADPCM_ON:TRUE VIDEO_ADPCM_OFF:FALSE) */
        vp_config.pMPGetMemInfo = NULL;
        vp_config.pSrcAspRatioChange_CallBack = NULL;//api_Scart_Aspect_Switch;

        tve_config.config = YUV_SMPTE | TVE_TTX_BY_VBI | TVE_CC_BY_VBI;

        tve_config.config |= TVE_NEW_CONFIG_1;
        tve_config.tve_tbl_all = tve_table_total;
        m36g_vpo_attach ( &vp_config, &tve_config );


        vcap_attach_t vcap_param;
        vcap_param.fb_addr = __MM_VCAP_FB_ADDR;//0xa2d67e00;
        vcap_param.fb_size = __MM_VCAP_FB_SIZE;//0x40b000;
        m36g_vcap_attach ( &vcap_param );

        sd_tve_config.config = YUV_SMPTE | TVE_TTX_BY_VBI | TVE_CC_BY_VBI;


        sd_tve_config.tve_adjust = g_sd_tve_adjust_table;
        sd_tve_config.tve_adjust_adv = tve_sd_adjust_table_adv;
        m36g_vpo_sd_attach ( &vp_config, &sd_tve_config );

}

static void vdec_dev_attach ( void )
{
        /* !!!!!Note !!!!!
                If you copy this code to other project, please check feature configuration firstly
             !!!!!Note !!!!!
        */
        struct vdec_config_par vdec_config_par;



        MEMSET ( ( void * ) &vdec_config_par, 0, sizeof ( struct vdec_config_par ) );

        //vdec_config_par.mem_map.frm0_Y_size  = 0;
        vdec_config_par.mem_map.frm0_Y_size  =  __MM_FB_LEN;//0x10cf200;
        vdec_config_par.mem_map.frm0_C_size = 0;
        vdec_config_par.mem_map.frm1_Y_size  = 0;
        vdec_config_par.mem_map.frm1_C_size = 0;
        vdec_config_par.mem_map.frm2_Y_size = 0;
        vdec_config_par.mem_map.frm2_C_size = 0;

        vdec_config_par.mem_map.frm0_Y_start_addr = __MM_FB_START_ADDR;//0xa6c6c200;
        vdec_config_par.mem_map.frm0_C_start_addr = 0;
        vdec_config_par.mem_map.frm1_Y_start_addr = 0;
        vdec_config_par.mem_map.frm1_C_start_addr = 0;
        vdec_config_par.mem_map.frm2_Y_start_addr = 0;
        vdec_config_par.mem_map.frm2_C_start_addr = 0;


        vdec_config_par.mem_map.dvw_frm_size = 0;
        vdec_config_par.mem_map.dvw_frm_start_addr = 0;

        vdec_config_par.mem_map.maf_size = __MM_MAF_LEN;//0x198c00;
        vdec_config_par.mem_map.maf_start_addr = __MM_MAF_START_ADDR;//0xa7d3b400;

        vdec_config_par.mem_map.vbv_size = ((__MM_VBV_LEN-4)&0xFFFFFF00);//0x12bf00;
        vdec_config_par.mem_map.vbv_start_addr = \
        ((__MM_VBV_START_ADDR&0xfffffff)|0x80000000);//0x87ed4000;
        vdec_config_par.mem_map.vbv_end_addr =((vdec_config_par.mem_map.vbv_start_addr) +  vdec_config_par.mem_map.vbv_size - 1);// 0x87fffeff;

        vdec_config_par.user_data_parsing = TRUE; /* macro USER_DATA_PARSING */
        vdec_config_par.dtg_afd_parsing = 0;     //SUPPORT_AFD_SCALE
        vdec_config_par.drop_freerun_pic_before_firstpic_show = FALSE; /* macro VDEC27_DROP_FREERUN_BEFORE_FIRSTSHOW */
        vdec_config_par.reset_hw_directly_when_stop = TRUE;  /* macro VDEC27_STOP_REST_HW_DIRECTLY*/
        vdec_config_par.show_hd_service = FALSE;      /* macro SUPPORT_SHOW_HD_SERVICE */
        vdec_config_par.still_frm_in_cc = FALSE;          /* macro STILL_FRAME_IN_CC */
        vdec_config_par.not_show_mosaic = FALSE;      /* macro VDEC_AVOID_MOSAIC_BY_FREEZE_SCR */
        vdec_config_par.adpcm.adpcm_mode = FALSE;  /* macro VIDEO_ADPCM_ONOFF(VIDEO_ADPCM_ON:TRUE VIDEO_ADPCM_OFF:FALSE)*/
        vdec_config_par.adpcm.adpcm_ratio = 0;
        vdec_config_par.sml_frm.sml_frm_mode = FALSE;  /* macro VDEC27_SML_FRM_ONOFF(VDEC27_SML_FRM_OFF: FALSE   VDEC27_SML_FRM_ON: TRUE)*/
        vdec_config_par.return_multi_freebuf = TRUE;        /* macro VDEC27_SUPPORT_RETURN_MULTI_FREEBUF */
        vdec_config_par.sml_frm.sml_frm_size = 0;           /* macro VDEC27_SML_FRM_SIZE*/
        vdec_config_par.lm_shiftthreshold = 2;                   /* macro VDEC27_LM_SHIFTTHRESHOLD*/
        vdec_config_par.vp_init_phase = 0;                        /* macro DEFAULT_MP_FILTER_ENABLE*/
        vdec_config_par.preview_solution = VDEC27_PREVIEW_DE_SCALE; /* macro VDEC27_PREVIEW_SOLUTION(VDEC27_PREVIEW_VE_SCALE or VDEC27_PREVIEW_DE_SCALE)*/
        vdec_m36_attach ( &vdec_config_par );
}

UINT8 api_get_chunk_add_len ( UINT32 id, UINT32* addr, UINT32* len )
{
        INT32 ret;
        CHUNK_HEADER chuck_hdr;

        ret = sto_get_chunk_header ( id, &chuck_hdr );
        if ( ret == 0 )
                return 0;

        *addr = ( UINT32 ) sto_chunk_goto ( &id, 0xFFFFFFFF, 1 ) + CHUNK_HEADER_SIZE;
        *len = chuck_hdr.len - CHUNK_HEADER_SIZE + CHUNK_NAME;

        return 1;
}

#define  LOGO_ID_TYPE 0x02FD0000
#define  LOGO_ID                        (LOGO_ID_TYPE | 0x0100)
#define  MENU_LOGO_ID   (LOGO_ID_TYPE | 0x0100)
#define  RADIO_LOGO_ID  (LOGO_ID_TYPE | 0x0100)
#define  MEDIA_LOGO_ID  (LOGO_ID_TYPE | 0x0100)
#define  BOOT_LOGO_ID   (LOGO_ID_TYPE | 0x0100)
void api_show_bootup_logo ( void )
{
        int i;
        void* pWriteBuffer;
        UINT32 uSizeGot;
        RET_CODE ret_code;
        UINT32 logo_id, addr, len;
        struct sto_device *sto_flash_dev;

        logo_id = BOOT_LOGO_ID;
        if ( api_get_chunk_add_len ( logo_id, &addr, &len ) == 0 )
                return;

        ret_code = vdec_start ( ( struct vdec_device * ) dev_get_by_id ( HLD_DEV_TYPE_DECV, 0 ) );
        
        sto_flash_dev = ( struct sto_device * ) dev_get_by_id ( HLD_DEV_TYPE_STO, 0 );
        for ( i = 0; i < 4; i++ )
        {
                ret_code = vdec_vbv_request ( g_decv_dev, len,     &pWriteBuffer, &uSizeGot, NULL );
                sto_get_data ( sto_flash_dev, ( UINT8 * ) pWriteBuffer, addr, uSizeGot );

                vdec_vbv_update ( g_decv_dev, uSizeGot );
        }
        
}

#undef  HDMI_SCREEN_CTL
#undef  HDMI_REG_CFG5
#undef  B_NORMAL_MONO_SEL
#undef  HDMI_CTR_REG
#undef  B_MUTETYPE_SEL
#undef  B_VCAP_RST
#undef  B_AV_MUTE
#undef  B_PDB
#define HDMI_CTR_REG                            (*(volatile UINT8*)(0xb802a000 + 0x07))
#define HDMI_REG_CFG5                           (*(volatile UINT8*)(0xb802a000 + 0x0E))
#define HDMI_SCREEN_CTL                 (*(volatile UINT8*)(0xb802a000 + 0x55))
#define B_NORMAL_MONO_SEL               0x40
#define B_MUTETYPE_SEL                  0x40
#define B_VCAP_RST                                      0x01
#define B_AV_MUTE                                       0x80
#define B_PDB                                           0x02
static void close_hdmi_output ( void )
{
        int i = 0;
        int cnt = 3;
        for ( i = 0; i < cnt; i ++ )
        {
                if ( HDMI_REG_CFG5 & B_MUTETYPE_SEL )
                {
                        HDMI_CTR_REG &= ~B_AV_MUTE;
                        osal_delay ( 5 );
                        HDMI_CTR_REG |= B_AV_MUTE;
                }
                else
                        HDMI_CTR_REG |= B_AV_MUTE;

                osal_delay ( 10 );
        }

        HDMI_SCREEN_CTL |= B_NORMAL_MONO_SEL;           //set hdmi mono screen(black).
}

static void video_dev_close ( void )
{
        struct  YCbCrColor bgcolor;

        if ( g_vpo_dev )
                vpo_win_onoff ( g_vpo_dev, FALSE );

        if ( g_sd_vpo_dev )
                vpo_win_onoff ( g_sd_vpo_dev, FALSE );

        bgcolor.uY = 16;
        bgcolor.uCb = 128;
        bgcolor.uCr = 128;
        if ( g_vpo_dev );
        vpo_ioctl ( g_vpo_dev, VPO_IO_SET_BG_COLOR, ( UINT32 ) &bgcolor );
        if ( g_vpo_dev )
                vdec_close ( g_decv_dev );
}

static void cleanup_hw_rest ( void )
{
        video_dev_close();
        close_hdmi_output();
}

#define VOU_CTRL      (*((volatile UINT32*)(0xb8006000)))
#define VOU_CFG_HDMI  (*((volatile UINT32*)(0xb8006080)))
void AppInit ( void )
{
        UINT8  ch, *t1, *t2, i;
        UINT32 boot_tick;
        UINT32 chid;
        UINT32 offset, offset1 = 0, offset2 = 0;
        UINT8 *main_entry, *see_entry, *see_ram_address;
        UINT8  boot_type;
        UINT32 boot_code, tmp, data;
#ifdef CI_PLUS_SUPPORT
        UINT32 maincode_len, maincode_addr, len_left;
        UINT8 maincode_left[32];
#endif

        UINT32 expand_start=0;
        UINT32 expand_end=0;
        UINT32 expand_time=0;
        struct de2Hdmi_video_infor LlvS;
        LlvS.tv_mode = 10;
        LlvS.afd_present = TRUE;
        LlvS.scan_mode = FALSE;
        LlvS.format = 4;
        LlvS.output_aspect_ratio = 0;
        LlvS.active_format_aspect_ratio = 8;
        LlvS.width = 1920;
        LlvS.height = 1080;
        LlvS.av_chg_ste = HDMI_CB_NOTHING;

        boot_code = * ( UINT32 * ) ( 0xA0000110 );
        /* Cold bootup */
        boot_type = * ( UINT8 * ) ( SYS_FLASH_BASE_ADDR + HW_SET_BOOTTYPE );
        if ( ( boot_type & BOOT_TYPE_MASK ) && boot_code == 0xdead3bee )
        {
                /* If cold bootup and enter standby enabled, enter standby */
                sys_ic_enter_standby ( 0, 0 );
        }
        
        /* Initialize */
        bl_uart_init();
        bl_panel_init();
             
        bl_flash_init();
         bl_verify_sw();  
        dma_init();
        bl_GPIO_init();
        //fix Scart TV show logo is green screen.
        * ( ( volatile unsigned long * ) GPIO_REG ) |= (1 << 10);
        * ( ( volatile unsigned long * ) GPIO_REG ) |= (1 << 13);
        * ( ( volatile unsigned long * ) GPIO_REG ) |= (1 << 4);
        HAL_GPIO_BIT_DIR_SET(10, HAL_GPIO_O_DIR);
        HAL_GPIO_BIT_DIR_SET(4, HAL_GPIO_O_DIR);
        HAL_GPIO_BIT_DIR_SET(13, HAL_GPIO_O_DIR);

        HAL_GPIO_BIT_SET(13,0);
        HAL_GPIO_BIT_SET(10,1);
        HAL_GPIO_BIT_SET(4,0);

        vpo_dev_attach();
        vdec_dev_attach();
        avInit();
        avStart();        
        /************config_de**************/
        VOU_CTRL = VOU_CTRL & ( ~ ( 1 << 2 ) );
        osal_delay ( 5 );
        VOU_CFG_HDMI = VOU_CFG_HDMI | ( 1 << 20 );
        osal_delay ( 5 );
        VOU_CFG_HDMI = VOU_CFG_HDMI | 0x02;
        osal_delay ( 5 );
        VOU_CTRL = VOU_CTRL | ( 1 << 2 ) | 0x01;
        /**************config_de*************/
        api_show_bootup_logo();
        avEnd();
        hdmi_force_show ( &LlvS );
  
        if ( g_crc_bad == 0 || g_second_loader == 1 )
        {

#ifdef _OTA_E_
                if ( g_second_loader )
                {
                        chid = CHUNKID_SECLOADER;
                        offset2 = g_ota_offset;
                }
                else
#endif

                        if ( g_crc_bad == 0 )
                        {
                                /* If dynamic application load enable, try load this application */
                                if ( boot_code == 0xdead2bee )
                                {
                                        chid = * ( ( UINT32 * ) 0xA0000114 );
                                        offset = sto_chunk_goto ( &chid, * ( ( UINT32 * ) 0xA0000118 ), 1 );
                                }
                                else
                                {
                                        chid = CHUNKID_MAINCODE;
                                        offset2 = sto_chunk_goto ( &chid, CHUNKID_MAINCODE_MASK, 1 );
                                }
                        }
                main_entry = 0;
                if ( offset2 != 0 )
                {
                        expand_start=read_tsc();
                        main_entry = expand ( offset2, un7zip, MAIN_CODE );
                        expand_end=read_tsc();
                        FIXED_PRINTF("expand_start=%lu expand_end=%lu expand maincode time=%lu\n",expand_start, expand_end, (unsigned long)(((expand_end-expand_start)/US_TICKS))); 
                        
                }

                if ( main_entry != 0 )
                {
                        boot_tick = read_tsc();
                        do
                        {
                                if ( sci_read_tm ( SCI_FOR_RS232, &ch, 5 ) == SUCCESS && ch == 'c' )
                                        break;
                                else
                                        ch = 0;
                        }
                        while ( read_tsc() - boot_tick < WAIT_150MS );
                        //change for fast boot up
                        //while (read_tsc() - boot_tick < WAIT_300MS);

                        if ( ch != 'c' )
                        {
                                set_os_config();
                                FIXED_PRINTF ( "success!\n" );
                                //make sure show logo time >=4S for HDMI can output logo, we can adjust this time
                                expand_time=(expand_end-expand_start)/US_TICKS; //change to US
                                if(expand_time<4000000)
                                {
                                    FIXED_PRINTF("expand_time=%lu <4000000 need to delay=%lu\n",expand_time, (4000000-expand_time)/1000); 
                                    osal_task_sleep((4000000-expand_time)/1000);
                                }
                                cleanup_hw_rest();
                                osal_cache_flush_all();
                                exec ( main_entry );
                        }
                }
        }
        else
        {
                FIXED_PRINTF ( "Boot loader: CRC bad%d! \n", g_crc_bad );
                if ( ota_prog_restore() == 0 )
                {
                        //boot_logo();
                        /* re-check CRC and jump to maincode */
                        chid = CHUNKID_MAINCODE;
                        offset = sto_chunk_goto ( &chid, CHUNKID_MAINCODE_MASK, 1 );
                        main_entry = 0;
                        if ( offset != 0 )
                        {
                                main_entry = expand ( offset, un7zip, MAIN_CODE );
                        }
                        if ( main_entry != 0 )
                        {
                                clean_restore_data();/* clean backup data while restore ok */
                                set_os_config();
                                FIXED_PRINTF ( "5!\n" );
                                osal_cache_flush_all();
                                exec ( main_entry );
                        }
                }
        }
	 vdec_stop(g_decv_dev, 0, 0);
	 vpo_close ( g_vpo_dev);
	 vpo_close ( g_sd_vpo_dev);
        lib_ash_shell();
}
